package com.zx.idc.backend.gui.sys.service;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.zx.idc.backend.gui.api.ftp.BaseFtpOperatorFactory;
import com.zx.idc.backend.gui.api.ftp.FtpOperator;
import com.zx.idc.backend.gui.api.ftp.FtpClientConfig;
import com.zx.idc.common.exception.GlobalException;
import com.zx.idc.common.lang.PathUtil;
import com.zx.idc.common.spring.SpringConfigUtil;
import com.zx.idc.common.util.LocalDateTimeFormatUtil;
import com.zx.idc.common.util.ZipUtils;
import com.zx.idc.ds.config.dao.BackupSpringUtil;
import com.zx.idc.ds.sys.bean.DataBackupSetting;
import com.zx.idc.ds.sys.bean.OffSiteBackupSetting;
import com.zx.idc.ds.sys.entity.SysBackupLog;
import com.zx.idc.ds.sys.service.ISysBackupLogService;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Objects;

/**
 * 使用 ftp 备份的相关操作
 *
 * @author rxliuli
 */
@Service
public class SysBackupLogServiceOfFtp {
    private final Logger log = LoggerFactory.getLogger(getClass());
    @Autowired
    private ISysBackupLogService sysBackupLogService;
    @Autowired
    private BackupSpringUtil backupSpringUtil;

    /**
     * 手动备份
     *
     * @param dataBackupSetting
     * @param offSiteBackupSetting
     * @param userId               系统用户 id
     * @return 手动备份
     */
    public Boolean addManualBackup(DataBackupSetting dataBackupSetting, OffSiteBackupSetting offSiteBackupSetting, Integer userId) {
        final LocalDateTime now = LocalDateTime.now();
        final SysBackupLog sysBackupLog = new SysBackupLog("手动备份: " + LocalDateTimeFormatUtil.formatLocalDateTime(now, "yyyy-MM-dd hh:mm:ss"), now, userId);
        try {
            BaseFtpOperatorFactory.getInstance(new FtpClientConfig(offSiteBackupSetting.getBackupFtpUser(), offSiteBackupSetting.getBackupFtpHost(), offSiteBackupSetting.getBackupFtpPwd(), offSiteBackupSetting.getBackupFtpPort()));
        } catch (Exception e) {
            throw new GlobalException("异地备份设置存在错误", e);
        }
        return addBackup(sysBackupLog, offSiteBackupSetting, dataBackupSetting);
    }

    /**
     * 进行备份
     *
     * @param sysBackupLog         系统用户
     * @param offSiteBackupSetting
     * @param dataBackupSetting
     * @return 手动备份
     */
    public Boolean addBackup(SysBackupLog sysBackupLog, OffSiteBackupSetting offSiteBackupSetting, DataBackupSetting dataBackupSetting) {
        boolean result = sysBackupLogService.insert(sysBackupLog);
        // 使用本地备份
        final String filename = sysBackupLog.getId().toString();
        String localZipPath;
        try {
            final String tempPath = SpringConfigUtil.get("spring.servlet.multipart.location");
            final String zipPath = PathUtil.join(tempPath, filename);
            final File zipDir = new File(zipPath);
            zipDir.mkdirs();
            // 备份 SQL
            backupSpringUtil.exportSQL(zipPath, filename);
            // 备份 MongoDB
            //TODO MongoDB暂时不备份 因量太大导致挂机
            //backupSpringUtil.exportMongodb(PathUtil.join(zipPath, filename + "_" + "mongodb"));
            // 核验图片/通讯文件
            if (Objects.equals(dataBackupSetting.getBackupIcpPicture(), DataBackupSetting.STATUS_ENABLE)) {
                FileUtils.copyDirectoryToDirectory(new File(SpringConfigUtil.get("disk.storage.permanent.image")), zipDir);
            }
            if (Objects.equals(dataBackupSetting.getBackupIcpPicture(), DataBackupSetting.STATUS_ENABLE)) {
                FileUtils.copyDirectoryToDirectory(new File(SpringConfigUtil.get("disk.storage.permanent.comunication")), zipDir);
            }
            final File zipFile = new File(zipPath + ".zip");
            ZipUtils.doCompress(zipDir, zipFile);
            final String backupPath = SpringConfigUtil.get("backup.path");
            localZipPath = PathUtil.join(backupPath, zipFile.getName());
            FileUtils.moveFileToDirectory(zipFile, new File(backupPath), true);
            FileUtils.deleteDirectory(zipDir);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new GlobalException("备份文件失败", e);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new GlobalException("备份命令执行失败", e);
        }

        final boolean offSite = offSiteBackupSetting != null && StringUtils.isNotEmpty(offSiteBackupSetting.getBackupFtpHost());
        if (offSite) {
            // 使用 ftp 远程备份
            final FtpOperator ftpOperator = BaseFtpOperatorFactory.getInstance(new FtpClientConfig(offSiteBackupSetting.getBackupFtpUser(), offSiteBackupSetting.getBackupFtpHost(), offSiteBackupSetting.getBackupFtpPwd(), offSiteBackupSetting.getBackupFtpPort()));
            final File localFile = new File(localZipPath);
            String backupFtpPath = StringUtils.defaultIfEmpty(offSiteBackupSetting.getBackupFtpPath(), "/db_backup/");
            String remotePath;
            if ("/".equals(backupFtpPath.substring(backupFtpPath.length() - 1))) {
                remotePath = backupFtpPath + localFile.getName();
            } else {
                remotePath = backupFtpPath + "/" + localFile.getName();
            }
            final boolean putResult = ftpOperator.put(localFile, remotePath);
            result = result && putResult && sysBackupLogService.updateById(sysBackupLog.setOffSite(2).setPath(remotePath));
        }
        if (dataBackupSetting.getBackupIcpNum() > 0 && sysBackupLogService.selectCount(new SysBackupLog()) >= dataBackupSetting.getBackupIcpNum()) {
            Integer id = sysBackupLogService.selectOne(new EntityWrapper<>(new SysBackupLog()).setSqlSelect("id").orderBy("id", false).last("limit " + (dataBackupSetting.getBackupIcpNum() - 1) + ",1")).getId();
            sysBackupLogService.selectList(new EntityWrapper<>(new SysBackupLog()).setSqlSelect("id").lt("id", id)).forEach(vo -> sysBackupLogService.deleteBackup(vo.getId()));
        }
        return result;
    }

}
